package com.desaysv.svnotice;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 消息通知类
 *
 * @author uidq5208
 * @version 1.0
 * @date 2022-12-2 15:50
 * @since 1.0
 */
public final class MessageBlockQueue {
    /**
     * 日志TAG
     */
    private static final String TAG = "[queue]";
    /**
     * 主线程handler
     */
    private Handler mHandler = new Handler(Looper.getMainLooper());
    /**
     * 线程池
     */
    private ExecutorService mThreadPool;
    /**
     * 消息队列对象
     */
    private ArrayBlockingQueue<QueueEvent> mQueue;

    /**
     * 单例对象
     */
    private static final class MInstanceHolder {
        /**
         * 单例
         */
        @SuppressLint("StaticFieldLeak")
        static final MessageBlockQueue M_INSTANCE = new MessageBlockQueue();
    }

    /**
     * 获取单例对象
     *
     * @return 单例对象
     */
    public static MessageBlockQueue getInstance() {
        return MInstanceHolder.M_INSTANCE;
    }

    /**
     * 设置UIHandler
     *
     * @param context 上下文
     * @return MessageBlockQueue
     */
//    public MessageBlockQueue setHandler(Context context) {
//        if (mHandler == null) {
//            mHandler = new Handler(context.getApplicationContext().getMainLooper());
//        }
//        return this;
//    }

    /**
     * 构造函数
     */
    private MessageBlockQueue() {
        init();
    }

    private void init() {
        if (mThreadPool == null) {
            Log.i(TAG, "MessageBlockQueue: init");
            mThreadPool = Executors.newFixedThreadPool(100);
            int maxQueueCount = 100;
            mQueue = new ArrayBlockingQueue<>(maxQueueCount);
        }
        if (mHandler == null) {
            mHandler = new Handler(Looper.getMainLooper());
        }
    }

    /**
     * 开始队列服务
     */
    public void start() {
        if (mHandler == null) {
            init();
        }
        mThreadPool.execute(() -> {
            while (true) {
                QueueEvent queueEvent = null;
                try {
                    queueEvent = mQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (queueEvent == null) {
                    continue;
                }
                mMessageObservable.post(queueEvent);
            }
        });
    }

    /**
     * notify通知
     *
     * @param eventId 事件id
     * @param obj     通知内容
     */
    public synchronized void notify(int eventId, Object obj) {
        if (mThreadPool == null || mThreadPool.isShutdown()) {
            return;
        }
        mQueue.offer(new QueueEvent(eventId, obj));
    }

    /**
     * notify通知
     *
     * @param event 事件标识
     * @param obj   通知内容
     */
    public synchronized void notify(String event, Object obj) {
        if (mThreadPool == null || mThreadPool.isShutdown()) {
            return;
        }
        mQueue.offer(new QueueEvent(event, obj));
    }

    /**
     * 创建通知
     *
     * @param obj 通知内容
     */
    public synchronized void notify(Object obj) {
        if (mThreadPool == null || mThreadPool.isShutdown()) {
            return;
        }
        mMessageObservable.postBus(obj);
    }

    /**
     * 清空队列消息
     */
    public synchronized void clear() {
        if (mThreadPool == null || mThreadPool.isShutdown()) {
            return;
        }
        mQueue.clear();
    }

    /**
     * 停止队列服务
     */
    public void stop() {
        if (mThreadPool != null && !mThreadPool.isShutdown()) {
            mThreadPool.shutdown();
        }
        mThreadPool = null;
        mHandler = null;
        if (mQueue != null) {
            mQueue.clear();
        }
        mQueue = null;
        mMessageObservable.deleteObservers();

    }

    /**
     * 队列事件
     */
    public static class QueueEvent {
        /**
         * 事件类型
         */
        private String event;
        /**
         * 事件id
         */
        private int eventId;
        /**
         * 事件信息
         */
        private Object obj;

        /**
         * 构造函数
         *
         * @param event 事件
         * @param obj   事件信息
         */
        QueueEvent(String event, Object obj) {
            this.event = event;
            this.obj = obj;
        }

        /**
         * 构造函数
         *
         * @param eventId 事件id
         * @param obj     事件信息
         */
        QueueEvent(int eventId, Object obj) {
            this.eventId = eventId;
            this.obj = obj;
        }

        /**
         * 获取事件id
         *
         * @return String
         */
        public String getEvent() {
            return event;
        }


        /**
         * 获取事件id
         *
         * @return 事件id
         */
        public int getEventId() {
            return eventId;
        }

        /**
         * 获取事件信息
         *
         * @return 事件信息
         */
        public Object getObj() {
            return obj;
        }
    }

    /**
     * 观察者对象 start
     **/
    private final MessageObservable mMessageObservable = new MessageObservable();

    /**
     * 消息观察者对象
     */
    private static class MessageObservable extends Observable {
        /**
         * 消息对象
         */
        private final ConcurrentHashMap<Class, Vector<MessageSubscribeImpl>> mPools = new ConcurrentHashMap<>(6);

        /**
         * 获取消息池
         *
         * @return ConcurrentHashMap
         */
        public ConcurrentHashMap<Class, Vector<MessageSubscribeImpl>> getPools() {
            return mPools;
        }

        /**
         * 添加观察者对象
         *
         * @param cla  观察对象
         * @param impl 回调对象
         */
        public synchronized void addObserver(Class cla, MessageSubscribeImpl impl) {
            Vector<MessageSubscribeImpl> poolVc = mPools.get(cla);
            if (poolVc == null) {
                poolVc = new Vector<>();
            }
            if (!poolVc.contains(impl)) {
                poolVc.addElement(impl);
            }
            mPools.put(cla, poolVc);
        }

        /**
         * 移除观察者对象
         *
         * @param impl 回调对象
         */
        public synchronized void removeClaObs(MessageSubscribeImpl impl) {
            for (Class cla : mPools.keySet()) {
                Vector<MessageSubscribeImpl> arrLocal = mPools.get(cla);
                if (arrLocal.contains(impl)) {
                    mPools.get(cla).removeElement(impl);
                    break;
                }
            }
        }

        /**
         * 移除对象观察
         *
         * @param claz 需要移除的对象
         */
        public synchronized void clearByClaz(Class claz) {
            mPools.remove(claz);
        }

        /**
         * 消息通知
         *
         * @param arg 通知对象
         */
        private void notifyBusObservers(Object arg) {
            if (arg instanceof QueueEvent) {
                notifyObservers(arg);
                return;
            }
            Object[] arrLocal = null;
            Vector<MessageSubscribeImpl> obs = mPools.get(arg.getClass());
            if (obs != null) {
                synchronized (this) {
                    if (!hasChanged()) {
                        return;
                    }
                    arrLocal = obs.toArray();
                    clearChanged();
                }
                for (int i = arrLocal.length - 1; i >= 0; i--) {
                    ((Observer) arrLocal[i]).update(this, arg);
                }
            }
        }

        /**
         * 转发普通事件消息
         *
         * @param queueEvent 消息事件
         */
        public final void post(QueueEvent queueEvent) {
            setChanged();
            notifyObservers(queueEvent);
        }

        /**
         * 转发队列消息
         *
         * @param queueEvent 事件消息
         */
        public final void postBus(Object queueEvent) {
            setChanged();
            notifyBusObservers(queueEvent);
        }
    }

    /**
     * 观察对象接口
     *
     * @param <T> 观察对象泛型
     */
    private interface IMessageObserver<T> extends Observer {
        /**
         * 消息转发
         *
         * @param queueEvent 事件消息
         */
        void post(T queueEvent);
    }

    /**
     * 消息观察对象
     */
    public abstract static class MessageObserverImpl implements IMessageObserver<QueueEvent> {
        @Override
        public void update(Observable o, Object arg) {
            if (MessageBlockQueue.getInstance().mHandler != null) {
                MessageBlockQueue.getInstance().mHandler.post(() -> {
                    post((QueueEvent) arg);
                });
            } else {
                post((QueueEvent) arg);
            }
        }
    }

    /**
     * 消息队列观察对象
     *
     * @param <T> 观察对象
     */
    public abstract static class MessageSubscribeImpl<T> implements IMessageObserver<T> {
        @Override
        public void update(Observable o, Object arg) {
            if (MessageBlockQueue.getInstance().mHandler != null) {
                MessageBlockQueue.getInstance().mHandler.post(() -> {
                    post((T) arg);
                });
            } else {
                post((T) arg);
            }
        }
    }

    /**
     * 添加观察对象
     *
     * @param observer
     */
    public void addObserver(MessageObserverImpl observer) {
        mMessageObservable.addObserver(observer);
    }

    /**
     * 订阅消息队列
     *
     * @param cla      订阅对象
     * @param observer 订阅回调
     */
    public void subscribe(Class cla, MessageSubscribeImpl observer) {
        mMessageObservable.addObserver(cla, observer);
    }

    /**
     * 取消队列订阅
     *
     * @param observer 需要取消的回调
     */
    public void unSubscribe(MessageSubscribeImpl observer) {
        mMessageObservable.removeClaObs(observer);
    }

    /**
     * 清空对象的订阅
     *
     * @param claz 清空的对象类
     */
    public void clearSubscribe(Class claz) {
        mMessageObservable.clearByClaz(claz);
    }

    /**
     * 移除观察对象
     *
     * @param observer 观察者
     */
    public void removeObserver(MessageObserverImpl observer) {
        mMessageObservable.deleteObserver(observer);
    }
    /** 观察者对象 end **/

}
